home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / xvisrc.zip / MAP.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  10KB  |  479 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)map.c    2.1 (Chris & John Downey) 7/29/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     map.c
  14. * module function:
  15.     Keyboard input/pushback routines, "map" command.
  16.  
  17.     Note that we provide key mapping through a different interface,
  18.     so that cursor key mappings etc do not show up to the user.
  19.     This works by having a two-stage process; first keymapping is
  20.     done, and then the result is fed through the normal mapping
  21.     process. The intent of the keymapping stage is to convert
  22.     machine-local keys into a standard form.
  23.  
  24. * bug:
  25.     If a map fails, we just pass all characters which had already
  26.     been accepted, plus the character which caused the mismatch,
  27.     straight through. This is not quite correct because we might
  28.     have got a good match starting at the very next character, i.e.
  29.     if we have mapped
  30.  
  31.         foo    to    bar
  32.  
  33.     and get input "ffoo", then the seconf 'f' will cause the map to
  34.     fail and both characters will go through, and so the whole thing
  35.     will pass through unmapped.
  36.  
  37.     The only way around this problem is to introduce another flexbuf
  38.     on the input side of the keymap stage, to give us somewhere to
  39.     put all characters after the first, when a map fails. I.e. in the
  40.     case above, we would pass the first 'f' through to the "mp_dest"
  41.     flexbuf, and stuff any characters after that into "mp_src".
  42.  
  43. * history:
  44.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  45.     Originally by Tim Thompson (twitch!tjt)
  46.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  47.     Heavily modified by Chris & John Downey
  48.  
  49. ***/
  50.  
  51. #include "xvi.h"
  52.  
  53. /*
  54.  * This is the fundamental structure type which is used
  55.  * to hold mappings from one string to another.
  56.  */
  57. typedef struct map {
  58.     struct map        *m_next;
  59.     char        *m_lhs;        /* lhs of map */
  60.     char        *m_rhs;        /* rhs of map */
  61.     unsigned int    m_same;        /* no characters same as next map */
  62. } Map;
  63.  
  64. /*
  65.  * This structure holds a current position while scanning a map list.
  66.  * It is also effectively used to form a chain of mapping structures,
  67.  * interconnected with flexbufs.
  68.  */
  69. typedef struct mpos {
  70.     Map        *mp_map;
  71.     int        mp_index;
  72.     Flexbuf    *mp_src;
  73.     Flexbuf    *mp_dest;
  74. } Mpos;
  75.  
  76. /*
  77.  * Two mapping structures exist; one for "map", and one for "map!".
  78.  */
  79. static    Map    *cmd_map = NULL;
  80. static    Map    *ins_map = NULL;
  81. static    Map    *key_map = NULL;
  82.  
  83. /*
  84.  * This is the position in cmd_map/ins_map when we are waiting for
  85.  * the next character. When not waiting, mp_map is NULL (as at start).
  86.  * Also stores flexbuf pointers for input and output at each stage.
  87.  */
  88. static    Flexbuf    getcbuff;
  89. static    Flexbuf inputbuff;
  90. static    Mpos    npos = { NULL, 0, &inputbuff,    &getcbuff };
  91. static    Mpos    kpos = { NULL, 0, NULL,        &inputbuff };
  92.  
  93. /*
  94.  * This is used for "display" mode; it records the current map which
  95.  * is being displayed. It is used by show_map().
  96.  */
  97. static    Map    *curmap;
  98. static    char    *show_map P((void));
  99.  
  100. static    void    mapthrough P((void));
  101. static    bool_t    process_map P((int, Mpos *));
  102. static    void    calc_same P((Map *));
  103. static    void    map_failed P((Mpos *));
  104. static    void    insert_map P((Map **, char *, char *, bool_t));
  105. static    void    delete_map P((Map **, char *));
  106.  
  107. /*VARARGS1*/
  108. /*PRINTFLIKE*/
  109. void
  110. stuff
  111. #ifdef    __STDC__
  112.     (char *format, ...)
  113. #else /* not __STDC__ */
  114.     (format, va_alist)
  115.     char    *format;
  116.     va_dcl
  117. #endif
  118. {
  119.     va_list    argp;
  120.  
  121.     VA_START(argp, format);
  122.     (void) vformat(npos.mp_dest, format, argp);
  123.     va_end(argp);
  124. }
  125.  
  126. int
  127. map_getc()
  128. {
  129.     return(flexempty(npos.mp_dest) ? EOF : flexpopch(npos.mp_dest));
  130. }
  131.  
  132. void
  133. map_char(c)
  134. register int    c;
  135. {
  136.     /*
  137.      * Send the input character through the keymap list.
  138.      */
  139.     if (kpos.mp_map == NULL) {
  140.         kpos.mp_map = key_map;
  141.     kpos.mp_index = 0;
  142.     }
  143.     if (process_map(c, &kpos) == FALSE) {
  144.     /*
  145.      * Send resulting output through the normal map list.
  146.      */
  147.     kpos.mp_map = NULL;
  148.     mapthrough();
  149.     }
  150. }
  151.  
  152. /*
  153.  * Process any characters in the input buffer through the
  154.  * cmd_map/ins_map lists into the output buffer, whence
  155.  * characters go into the editor itself.
  156.  */
  157. static void
  158. mapthrough()
  159. {
  160.     while (!flexempty(npos.mp_src)) {
  161.     if (npos.mp_map == NULL) {
  162.         if (State == NORMAL) {
  163.         npos.mp_map = cmd_map;
  164.         } else if (State == INSERT || State == REPLACE) {
  165.         npos.mp_map = ins_map;
  166.         }
  167.         npos.mp_index = 0;
  168.     }
  169.  
  170.     if (process_map(flexpopch(npos.mp_src), &npos) == FALSE) {
  171.         npos.mp_map = NULL;
  172.     }
  173.     }
  174. }
  175.  
  176. /*
  177.  * Process the given character through the maplist pointed to
  178.  * by the given position. Returns TRUE if we should continue,
  179.  * or FALSE if this attempt at mapping has terminated (either
  180.  * due to success or definite failure).
  181.  */
  182. static bool_t
  183. process_map(c, pos)
  184. register int    c;
  185. register Mpos    *pos;
  186. {
  187.     register Map    *tmp;
  188.     register int    ind;
  189.  
  190.     ind = pos->mp_index;
  191.     for (tmp = pos->mp_map; tmp != NULL; tmp = tmp->m_next) {
  192.     if (tmp->m_lhs[ind] == c) {
  193.         if (tmp->m_lhs[ind + 1] == '\0') {
  194.         /*
  195.          * Found complete match. Insert the result into
  196.          * the appropriate output buffer, according to
  197.          * whether "remap" is set or not.
  198.          */
  199.         (void) lformat((Pb(P_remap) && pos->mp_src != NULL) ?
  200.                 pos->mp_src : pos->mp_dest, "%s", tmp->m_rhs);
  201.         return(FALSE);
  202.         } else {
  203.         /*
  204.          * Found incomplete match,
  205.          * keep going.
  206.          */
  207.         pos->mp_map = tmp;
  208.         pos->mp_index++;
  209.         }
  210.         return(TRUE);
  211.     }
  212.  
  213.     /*
  214.      * Can't move on to next map entry unless the m_same
  215.      * field is sufficient that the match so far would
  216.      * have worked.
  217.      */
  218.     if (tmp->m_same < ind) {
  219.         break;
  220.     }
  221.     }
  222.  
  223.     map_failed(pos);
  224.  
  225.     /*
  226.      * Don't forget to re-stuff the character we have just received.
  227.      */
  228.     (void) flexaddch(pos->mp_dest, c);
  229.     return(FALSE);
  230. }
  231.  
  232. void
  233. map_timeout()
  234. {
  235.     if (kpos.mp_map != NULL) {
  236.     map_failed(&kpos);
  237.     mapthrough();
  238.     } else {
  239.         map_failed(&npos);
  240.     }
  241. }
  242.  
  243. bool_t
  244. map_waiting()
  245. {
  246.     return(kpos.mp_map != NULL || npos.mp_map != NULL);
  247. }
  248.  
  249. /*
  250.  * This routine is called when a timeout has occurred.
  251.  */
  252. static void
  253. map_failed(pos)
  254. Mpos    *pos;
  255. {
  256.     register char    *cp;
  257.     register Flexbuf    *fbp;
  258.     register int    i;
  259.  
  260.     if (pos->mp_map != NULL) {
  261.     fbp = pos->mp_dest;
  262.     for (i = 0, cp = pos->mp_map->m_lhs; i < pos->mp_index; i++) {
  263.         (void) flexaddch(fbp, cp[i]);
  264.     }
  265.     pos->mp_map = NULL;
  266.     }
  267. }
  268.  
  269. /*
  270.  * Insert the key map lhs as mapping into rhs.
  271.  */
  272. void
  273. xvi_keymap(lhs, rhs)
  274. char    *lhs;
  275. char    *rhs;
  276. {
  277.     insert_map(&key_map, lhs, rhs, FALSE);
  278. }
  279.  
  280. /*
  281.  * Insert the entry "lhs" as mapping into "rhs".
  282.  */
  283. void
  284. xvi_map(argc, argv, exclam, inter)
  285. int    argc;
  286. char    *argv[];
  287. bool_t    exclam;
  288. bool_t    inter;
  289. {
  290.     switch (argc) {
  291.     case 2:                /* valid input */
  292.     if (argv[0][0] == '\0') {
  293.         if (inter) {
  294.         show_message(curwin, "Usage: map lhs rhs");
  295.         }
  296.         return;
  297.     }
  298.     insert_map(exclam ? &ins_map : &cmd_map, argv[0], argv[1], inter);
  299.     break;
  300.  
  301.     case 0:
  302.     curmap = exclam ? ins_map : cmd_map;
  303.     disp_init(curwin, show_map, (int) curwin->w_ncols, FALSE);
  304.     break;
  305.  
  306.     default:
  307.     if (inter) {
  308.         show_message(curwin, "Wrong number of arguments to map");
  309.     }
  310.     }
  311. }
  312.  
  313. static void
  314. insert_map(maplist, left, right, interactive)
  315. Map        **maplist;
  316. char        *left;
  317. char        *right;
  318. bool_t        interactive;
  319. {
  320.     char    *lhs;            /* saved lhs of map */
  321.     char    *rhs;            /* saved rhs of map */
  322.     Map        *mptr;            /* new map element */
  323.     Map        **p;            /* used for loop to find position */
  324.     int        rel;
  325.  
  326.     lhs = strsave(left);
  327.     if (lhs == NULL || (rhs = strsave(right)) == NULL) {
  328.     if (interactive) {
  329.         show_message(curwin, "no memory for that map");
  330.     }
  331.     return;
  332.     }
  333.  
  334.     mptr = (Map *) alloc(sizeof(Map));
  335.     if (mptr == NULL) {
  336.     free(lhs);
  337.     free(rhs);
  338.     return;
  339.     }
  340.  
  341.     mptr->m_lhs = lhs;
  342.     mptr->m_rhs = rhs;
  343.  
  344.     p = maplist;
  345.     if ((*p) == NULL || strcmp((*p)->m_lhs, lhs) > 0) {
  346.     /*
  347.      * Either there are no maps yet, or the one
  348.      * we want to enter should go at the start.
  349.      */
  350.     mptr->m_next = *p;
  351.     *p = mptr;
  352.     calc_same(mptr);
  353.     } else if (strcmp((*p)->m_lhs, lhs) == 0) {
  354.     /*
  355.      * We need to replace the rhs of the first map.
  356.      */
  357.     free(lhs);
  358.     free((char *) mptr);
  359.     free((*p)->m_rhs);
  360.     (*p)->m_rhs = rhs;
  361.     calc_same(*p);
  362.     } else {
  363.     for ( ; (*p) != NULL; p = &((*p)->m_next)) {
  364.         /*
  365.          * Set "rel" to +ve if the next element is greater
  366.          * than the current one, -ve if it is less, or 0
  367.          * if they are the same (if the lhs is the same).
  368.          */
  369.         rel = ((*p)->m_next == NULL) ? 1 :
  370.         strcmp((*p)->m_next->m_lhs, lhs);
  371.  
  372.         if (rel >= 0) {
  373.         if (rel > 0) {
  374.             /*
  375.              * The right place to insert
  376.              * the new map.
  377.              */
  378.             mptr->m_next = (*p)->m_next;
  379.             (*p)->m_next = mptr;
  380.             calc_same(*p);
  381.             calc_same(mptr);
  382.         } else /* rel == 0 */ {
  383.             /*
  384.              * The lhs of the new map is identical
  385.              * to that of an existing map.
  386.              * Replace the old rhs with the new.
  387.              */
  388.             free(lhs);
  389.             free((char *) mptr);
  390.             mptr = (*p)->m_next;
  391.             free(mptr->m_rhs);
  392.             mptr->m_rhs = rhs;
  393.             calc_same(mptr);
  394.         }
  395.         return;
  396.         }
  397.     }
  398.     }
  399. }
  400.  
  401. void
  402. xvi_unmap(argc, argv, exclam, inter)
  403. int    argc;
  404. char    *argv[];
  405. bool_t    exclam;
  406. bool_t    inter;
  407. {
  408.     int    count;
  409.  
  410.     if (argc < 1) {
  411.     if (inter) {
  412.         show_message(curwin, "But what do you want me to unmap?");
  413.     }
  414.     return;
  415.     }
  416.  
  417.     for (count = 0; count < argc; count++) {
  418.     delete_map(exclam ? &ins_map : &cmd_map, argv[count]);
  419.     }
  420. }
  421.  
  422. static void
  423. delete_map(maplist, lhs)
  424. Map    **maplist;
  425. char    *lhs;
  426. {
  427.     Map    *p;
  428.  
  429.     p = *maplist;
  430.     if (p != NULL && strcmp(p->m_lhs, lhs) == 0) {
  431.     *maplist = p->m_next;
  432.     } else {
  433.     for (; p != NULL; p = p->m_next) {
  434.         if (p->m_next != NULL && strcmp(lhs, p->m_next->m_lhs) == 0) {
  435.         Map    *tmp;
  436.  
  437.         tmp = p->m_next;
  438.         p->m_next = p->m_next->m_next;
  439.         free(tmp->m_lhs);
  440.         free(tmp->m_rhs);
  441.         free((char *) tmp);
  442.         calc_same(p);
  443.         }
  444.     }
  445.     }
  446. }
  447.  
  448. static void
  449. calc_same(mptr)
  450. Map    *mptr;
  451. {
  452.     register char    *a, *b;
  453.  
  454.     mptr->m_same = 0;
  455.     if (mptr->m_next != NULL) {
  456.     for (a = mptr->m_lhs, b = mptr->m_next->m_lhs; *a == *b; a++, b++) {
  457.         mptr->m_same++;
  458.     }
  459.     }
  460. }
  461.  
  462. static char *
  463. show_map()
  464. {
  465.     static Flexbuf    buf;
  466.  
  467.     /*
  468.      * Have we reached the end?
  469.      */
  470.     if (curmap == NULL) {
  471.     return(NULL);
  472.     }
  473.  
  474.     flexclear(&buf);
  475.     (void) lformat(&buf, "%-18.18s %-s", curmap->m_lhs, curmap->m_rhs);
  476.     curmap = curmap->m_next;
  477.     return flexgetstr(&buf);
  478. }
  479.